#include<iostream>
#include<sys/select.h>
#include<string>
#include<unistd.h>
#include<time.h>
#include"Socket.hpp"
#include"Log.hpp"

#define BITS 8 
#define NUM (sizeof(fd_set)*BITS)

#define FD_NONE -1

class SelectServer
{
private:
    int _listen_sock ;
    uint16_t _port;
    int _fd_array[NUM];

public:
    SelectServer(const uint16_t& port = 8081): _port(port)
    {
        _listen_sock = Socket::GetSocket();
        Socket::Bind(_listen_sock,_port);
        Socket::Listen(_listen_sock);
        DLOG("%s\n","create socket success");

        //初始化_fd数组的内容
        for(int i = 0 ; i < NUM ; i++)
            _fd_array[i] = FD_NONE; 

        _fd_array[0] = _listen_sock; //监听套接字默认第一个          
    }

    //Runing....
    void Start()
    {
        while(true)
        {
            DebugPrint();

            //创建一个输入位图
            fd_set rfds; 
            int max_fd = _listen_sock; //记录最大的套接字
            //把所有数组中有效的fd文件描述符加入进数组中
            for(int i = 0 ; i < NUM; i++)
            {
                if(_fd_array[i] == FD_NONE) continue;
                FD_SET(_fd_array[i], &rfds);
                if(_fd_array[i] > max_fd) max_fd = _fd_array[i]; //更新最大的套接字
            }

            int n = select(max_fd+1,&rfds,nullptr,nullptr,nullptr) ; 

            switch(n)
            {
                case 0:  DLOG("%s\n","time out....."); break;
                case -1: ELOG("select errno..... errno :  %d : %s\n",errno,strerror(errno)); break;
                default: DLOG("get a new link\n");
                         Handler(rfds);  //等待已就绪
                         break;

            }

        }
    }

    ~SelectServer()
    {
        close(_listen_sock);
    }

private:
    void DebugPrint()
    {
        std::cout << "_fd_array[] :" ;
        for(int i = 0 ; i < NUM ; i++)
        {
            if(_fd_array[i] == FD_NONE) continue; 
            std::cout << "  " << _fd_array[i];
        }
        std::cout << std::endl;
    }
    void Handler(fd_set& rfds)
    {
        //遍历数组
        for(int i = 0 ; i < NUM ; i++)
        {
            if(_fd_array[i] == FD_NONE) continue;
            if(FD_ISSET(_fd_array[i],&rfds)) //位图中是否存在当前fd
            {
                if(_fd_array[i] == _listen_sock) Accepter();  //是监听套接字处理accept
                else Recver(i); //是其他套接字就绪就进行读
            }
        }
    }

    void Accepter()
    {
        uint16_t client_port;
        std::string client_ip; 
        int sock = Socket::Accept(_listen_sock,&client_ip,&client_port);
        if(sock < 0 )
        {
            DLOG("Accept Sock Fail\n");
            return ;
        }
        DLOG("get a new link success\n");

        int pos = 1; 
        for(; pos < NUM ; pos++) //0位置默认为listen_sock,所以从1开始遍历
        {
            if(_fd_array[pos] == FD_NONE) break; //找到一个为空的位置
        }
        if(pos == NUM) //位置已满
        {
           DLOG("_fd_array already full\n");
           close(sock);
           return;
        }
        
        //把套接字添加进pos下标位置
        _fd_array[pos] = sock; 
    }

    void Recver(int pos)
    {
        char buff[128] = {0}; 
        int n = recv(_fd_array[pos],buff,sizeof(buff) - 1 , 0); 
        if(n > 0)
        {
            //读取成功
            buff[n] = '\0';
            DLOG("client [%d]# %s\n",_fd_array[pos] , buff);
        }else if(n == 0)
        {
            //对端关闭
            DLOG("client[%d] quit, me too...\n",_fd_array[pos]);
            close(_fd_array[pos]);
            _fd_array[pos] = FD_NONE;
        }else
        {
            //读取错误
            DLOG("client[%d] recv error, %d : %s\n",_fd_array[pos],errno,strerror(errno));
            close(_fd_array[pos]);
            _fd_array[pos] = FD_NONE;
        }
    }

};

